← All Articles

[BAEKJOON] 1774. 우주신과의 교감

Posted on

문제 :

황선자씨는 우주신과 교감을 할수 있는 채널러 이다. 하지만 우주신은 하나만 있는 것이 아니기때문에 황선자 씨는 매번 여럿의 우주신과 교감하느라 힘이 든다. 이러던 와중에 새로운 우주신들이 황선자씨를 이용하게 되었다.

하지만 위대한 우주신들은 바로 황선자씨와 연결될 필요가 없다. 이미 황선자씨와 혹은 이미 우주신끼리 교감할 수 있는 우주신들이 있기 때문에 새로운 우주신들은 그 우주신들을 거쳐서 황선자 씨와 교감을 할 수 있다.

우주신들과의 교감은 우주신들과 황선자씨 혹은 우주신들 끼리 이어진 정신적인 통로를 통해 이루어 진다. 하지만 우주신들과 교감하는 것은 힘든 일이기 때문에 황선자씨는 이런 통로들이 긴 것을 좋아하지 않는다. 왜냐하면 통로들이 길 수록 더 힘이 들기 때문이다.

또한 우리들은 3차원 좌표계로 나타낼 수 있는 세상에 살고 있지만 우주신들과 황선자씨는 2차원 좌표계로 나타낼 수 있는 세상에 살고 있다. 통로들의 길이는 2차원 좌표계상의 거리와 같다.

이미 황선자씨와 연결된, 혹은 우주신들과 연결된 통로들이 존재한다. 우리는 황선자 씨를 도와 아직 연결이 되지 않은 우주신들을 연결해 드려야 한다. 새로 만들어야 할 정신적인 통로의 길이들이 합이 최소가 되게 통로를 만들어 “빵상”을 외칠수 있게 도와주자.


입력 :

첫째 줄에 우주신들의 개수(N<=1,000) 이미 연결된 신들과의 통로의 개수(M<=1,000)가 주어진다.

두 번째 줄부터 N개의 줄에는 황선자를 포함하여 우주신들의 좌표가 (0<= X<=1,000,000), (0<=Y<=1,000,000)가 주어진다. 그 밑으로 M개의 줄에는 이미 연결된 통로가 주어진다. 번호는 위의 입력받은 좌표들의 순서라고 생각하면 된다. 좌표는 정수이다.


출력 :

첫째 줄에 만들어야 할 최소의 통로 길이를 출력하라. 출력은 소수점 둘째짜리까지 출력하여라.




풀이 :

MST(Minimum Spanning Tree)를 구하는 문제이다.

기본적인 MST 문제와 조금의 차이가 있다면 현재 연결된 통로가 존재하며 추가적으로 통로를 연결해 현재 상태에서 최소 통로 길이를 구해야 한다.

크루스칼 알고리즘과 프림 알고리즘을 모두 사용할 수 있지만, 난 본 문제를 프림 알고리즘으로 접근했다.

[세부 구현사항]

  • 기본적인 프림 알고리즘을 사용한다. 우선 connected[1001] 배열을 통해 현재 해당 우주신의 연결 유무를 판단하고, mustConnect[1001][1001] 배열을 사용해 두 우주신 간에 필수 연결상태(이미 연결된 통로인지 유무)를 저장한다.
  • 1번 우주신부터 차례로 프림 알고리즘을 사용하여 가장 짧은 통로를 하나씩 추가해가며 MST를 완성시켜 나간다.
  • 기본 프림 알고리즘과 다른 구현 방법은 한 가지이다. mustConnect에 해당하는 필수 통로의 경우에는 우선순위 큐에 정보를 삽입할 때 거리를 0으로 저장해 삽입한다. 이와 같이 구현할 경우 해당 통로는 무조건 MST에 포함되게 되고 거리가 0이기 때문에 우리가 구해야하는 최소 추가 통로 길이에도 영향을 미치지 않기 때문에 기본 프림 알고리즘에서 약간의 변화로 문제를 해결할 수 있다.



코드 :

코드 보기/접기
#include <iostream>
#include <vector>
#include <utility>
#include <queue>
#include <cmath>

#define pii pair<int, int>
#define pdi pair<double, int>

using namespace std;
bool connected[1001], mustConnect[1001][1001];
int n;

int main() {
    vector<pii > posVec;
    priority_queue<pdi, vector<pdi >, greater<>> pq;
    int m, posX, posY, fir, sec, connectCnt = 0;
    double minDist = 0;
    cin >> n >> m;
    posVec.emplace_back(0, 0);

    for (int i = 0; i < n; i++) {
        cin >> posX >> posY;
        posVec.emplace_back(posX, posY);
    }

    while (m--) {
        cin >> fir >> sec;
        mustConnect[fir][sec] = true;
        mustConnect[sec][fir] = true;
    }

    pq.push(pdi(0, 1));
    while (connectCnt < n) {
        double curDist = pq.top().first;
        int curIdx = pq.top().second;
        pq.pop();
        if (connected[curIdx]) continue;
        connected[curIdx] = true;
        minDist += curDist;
        connectCnt++;
        for (int j = 1; j <= n; j++) {
            if (mustConnect[curIdx][j]) pq.push(pdi(0, j));
            else if (!connected[j])
                pq.push(pdi(sqrt(
                                    pow(posVec[curIdx].first - posVec[j].first, 2) +
                                    pow(posVec[curIdx].second - posVec[j].second, 2)),
                            j));
        }
    }
    cout << fixed;
    cout.precision(2);
    cout << minDist << '\n';
    return 0;
}



AlgorithmalgorithmbaekjoonC++